//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sched.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <aura.h>
#include <auraplus.h>
#include <linknode.h>
#include <pthread.h>

#include "thread.h"

#undef NULL
#include "private.h"

pthread_mutex_t threadLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t tlsLock    = PTHREAD_MUTEX_INITIALIZER;

static Aura_UInt64 s_TlsSlotFields;

extern Aura_ProcessId g_processId;

extern DLinkNode g_ThreadInfoList;

int mytest = 0;

pthread_key_t s_key;

void __attribute__((constructor)) process_init()
{
    int res = 0;

    res = pthread_key_create(&s_key, NULL);
    if (res < 0) {
        printf(" failed to call pthread_key_create.");
        return ;
    }

    ThreadInfo *pThreadInfo;
    pThreadInfo = new ThreadInfo();
    if(NULL == pThreadInfo){
        AURA_ERROR("out of memory.");
        return ;
    }

    pThreadInfo->m_iThreadId = (Aura_ThreadId)getpid();
    g_processId = pThreadInfo->m_iThreadId;

    res = pthread_setspecific(s_key, (void *)pThreadInfo);
    if (res < 0) {
        printf(" failed to call key set.");
        delete pThreadInfo;
        return ;
    }

    return;
}

void __attribute__((destructor)) process_fini()
{
    pthread_key_delete(s_key);
}


AURA_API AuraTls_Allocate(
    /* [out] */ Aura_UInt32 * pIndex)
{
    pthread_key_t * pKey = NULL;
    Aura_ECode ec = AURA_NOERROR;
    int res = 0;

    pKey = (pthread_key_t *)Aura_malloc(sizeof(pthread_key_t));
    if (NULL == pKey) {
        ec = AURA_E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }

    res = pthread_key_create(pKey, NULL);
    if (res < 0) {
        printf(" <%s> failed to call pthread_key_create.\n",__FUNCTION__);
        goto E_FAIL_EXIT;
    }

    *pIndex = (Aura_UInt32)pKey;
    return AURA_NOERROR;

E_FAIL_EXIT:
    if (NULL != pKey) {
        Aura_free(pKey);
    }
    return ec;
}

AURA_API AuraTls_Free(
    /* [in]  */ Aura_UInt32 uIndex)
{
    pthread_key_t * pKey = (pthread_key_t *)uIndex;
    int res = 0;

    res = pthread_key_delete(*pKey);
    if (res < 0) {
        printf(" failed to call pthread_key_delete (%d).\n", res);
        return AURA_E_FAIL;
    }

    Aura_free(pKey);
    return AURA_NOERROR;
}

AURA_API AuraTls_GetValue(
    /* [in]  */ Aura_UInt32 uIndex,
    /* [out] */ Aura_PVoid * ppValue)
{
    pthread_key_t * pKey = (pthread_key_t *)uIndex;
    void * pValue = NULL;

    pValue = pthread_getspecific(*pKey);
    if (NULL == pValue) {
        printf(" failed to call <getspecific> .\n");
        return AURA_E_FAIL;
    }

    *ppValue = pValue;
    return AURA_NOERROR;
}

AURA_API AuraTls_SetValue(
    /* [in]  */ Aura_UInt32 uIndex,
    /* [in]  */ Aura_PVoid pValue)
{
    pthread_key_t * pKey = (pthread_key_t *)uIndex;
    int res = 0;

    res = pthread_setspecific(*pKey, pValue);
    if (res < 0) {
        printf(" failed to call <setspecific> .\n");
        return AURA_E_FAIL;
    }

    return AURA_NOERROR;
}

